class P extends Parser;

options {
			k = 1;
	      	buildAST=true;
}

tokens
{
	PROGRAM;
	STMT_LIST;
	EXPR_LIST;
	FORMAL_LIST;
	FUNC_CALL;
	BREAK="break";
	CONTINUE="continue";
	RETURN="return";
	COORDINATE;
}

imaginaryTokenDefinitions:
    SIGN_PLUS
    SIGN_MINUS
    ;

program		   : (statement | funcdecl)* {System.out.println("accepted");}
			   ;
			
funcdecl	    : "function"^ ID LPAREN! formal_list RPAREN! LBRACE! statement RBRACE!
			    ;

formal_list	    : ID (COMMA ID)*
			    ;
			    
statement_list  : (statement)*
                ;
                
statement	:( if_statement
			| for_statement
			| forc_statement
			| forr_statement
			| while_statement
			| break_statement   
			| continue_statement
			| return_statement
			| expr_statement    
			| LBRACE! statement_list RBRACE!) {System.out.println("statement accepted");}
			;

if_statement	   : "if"^ LPAREN! expr RPAREN! statement (options {greedy = true;}: "else"! statement )?
			       ;

for_statement	   : "for"^ LPAREN! expr_list SEMI! (expr)? SEMI! expr_list RPAREN! statement
			       ;
			
forc_statement	   : "forc"^ coordinate ASSIGN! coordinate coordinate statement 			
				   ;
				
forr_statement	   : "forr"^ coordinate ASSIGN! coordinate coordinate statement 			
				   ;
								
while_statement	    : "while"^ LPAREN! expr RPAREN! statement
			        ;

break_statement	    : BREAK(SEMI!)
			        ;

continue_statement	: CONTINUE(SEMI!)
			        ;

return_statement	: RETURN^ (expr)? SEMI!
			        ;

expr_statement      : expr(SEM!)
                    ;
                    
expr 		    : logic_term ( OR^ logic_term)*
			    ;

logic_term 	    : logic_factor ( AND^ logic_factor)*
			    ;

logic_factor    : (NOT^)? rel_expr
			    ;

rel_expr 	    : arith_expr ( (GE^ | LE^ | GT^| LT^ | EQ^ | NE^ ) arith_expr)?
			    ;

arith_expr      : arith_term ( (PLUS^ | MINUS^) arith_term)*
			    ;

arith_term 	    : arith_factor ( (MUL^ | DIV^ | MOD^) arith_factor)*
			    ;
		
/*
 * We will also introduce POW. Deferring this to a later stage
 */		

arith_factor   :  (
                   p:PLUS^ { #p.setType(SIGN_PLUS);}
               |   m:MINUS^ { #m.setType(SIGN_MINUS);})? rvalue
			   ;
/*
arith_factor   :  rvalue
			   ;

*/

rvalue 		   : coordinate | NUM | ID | EURT | ESLAF 
			   | LPAREN! expr RPAREN!
			   ;
// | lvalue | func_call. The lvalue will be req for arrays. We are not
// supporting it for now. Todo on the function call as an EXPR
//;
//
// Commentind due to reasons said above
//lvalue : ID^ // TODO (a=b) || (
//;
//

coordinate 	 : LBRAC! (NUM|ID) COLON! (NUM|ID) RBRAC!
			 ;

expr_list	 : expr (COMMA! expr)* 
			 ;


class L extends Lexer;

options { k = 1;}

tokens
{
	INT_CONSTANT;
	REAL_CONSTANT;
}


protected DIGIT: '0'..'9';

ID options 
                {
                testLiterals = true; 
                }
        		: ( 'a'..'z' | 'A'..'Z' | '_' | '$')
                ( 'a'..'z' | 'A'..'Z' | '_' | '$' | '0'..'9' )*
        		;

                
NUM             : (DIGIT)+	('.' (DIGIT)+)*         
                ;
                
AND				: "&&" 
				;

LE				: "<=" 
				;
                
SEMI			: ';'
				;
				
OR				: "||"
				;
				
GT				: '>'
				;

LPAREN          : '('
                ;

ASSIGN          :  '='
                ;
                
GE				: ">="
				;          
                
RPAREN          : ')'
                ;				
				 
EQ				: "=="
				;
				
LBRACE			: '{'
				;
		
PLUS			: '+'
				;
				
NOT				: '!'
				;		
				
RBRACE			: '}'
               	;
                     
MINUS			: '-'
				;
				
NE 				: "!="
				;
				
LBRAC           : '['
                ;
              
MUL				: '*'
				;
				
MOD				: '%'
				;
				
LT				: '<'
				;

RBRAC	       	: ']'
               	;
      
DIV				: '/'
				;       
               	
COLON           : ':'
                ;
                
COMMA			: ','
				;

				
WS              : (' ' | '\t')+ {$setType(Token.SKIP);}; 

NL 				: ('\n' {newline(); }
                | ('\r' '\n') => '\r' '\n' {newline();}
                | '\r') {$setType(Token.SKIP);}
				; 

COMMENT	        : "/*" ( options { generateAmbigWarnings = false; }	: { LA(2) != '/' }? '*' 
                | "\r\n" { newline(); } 
                | ( '\r' | '\n' ) { newline(); } 
                | ~( '*'| '\r' | '\n' ))* "*/" { $setType(Token.SKIP); }
		        ;
